{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Download Any OSM Geospatial Features with OSMnx\n",
    "\n",
    "Author: [Geoff Boeing](https://geoffboeing.com/)\n",
    "\n",
    "More info:\n",
    "\n",
    "  - [Documentation](https://osmnx.readthedocs.io/)\n",
    "  - [Journal article and citation info](https://geoffboeing.com/publications/osmnx-paper/)\n",
    "  - [Code repository](https://github.com/gboeing/osmnx)\n",
    "  - [Examples gallery](https://github.com/gboeing/osmnx-examples)\n",
    "  \n",
    "This notebook provides a quick tour of using OSMnx to download any geospatial features from OpenStreetMap as a geopandas GeoDataFrame."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import osmnx as ox\n",
    "import pandas as pd\n",
    "\n",
    "ox.__version__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Use the `geometries` module to download features, such as grocery stores, transit stops, points of interest, or building footprints, and turn them into a GeoDataFrame: [see docs](https://osmnx.readthedocs.io/en/stable/osmnx.html#module-osmnx.geometries).\n",
    "\n",
    "To query, pass a `tags` dict where keys are OSM tags. The dict's values can be either:\n",
    "  1. `True` to retrieve all OSM objects with this tag, regardless of its value\n",
    "  2. a single value as a string to retrieve all OSM objects with this tag:value combination\n",
    "  3. a list of string values to retrieve all OSM objects where this tag matches any of these values\n",
    "\n",
    "Pass multiple dict key:value pairs to retrieve the union (not intersection) of these pairs."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# get all building footprints in some neighborhood\n",
    "# `True` means retrieve any object with this tag, regardless of value\n",
    "place = \"Chinatown, San Francisco, California\"\n",
    "tags = {\"building\": True}\n",
    "gdf = ox.features.features_from_place(place, tags)\n",
    "gdf.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fig, ax = ox.plot.plot_footprints(gdf, figsize=(3, 3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# get all the parks in some neighborhood\n",
    "# constrain acceptable `leisure` tag values to `park`\n",
    "tags = {\"leisure\": \"park\"}\n",
    "gdf = ox.features.features_from_place(place, tags)\n",
    "gdf.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# get everything tagged amenity,\n",
    "# and everything tagged landuse = retail or commercial,\n",
    "# and everything tagged highway = bus_stop\n",
    "tags = {\"amenity\": True, \"landuse\": [\"retail\", \"commercial\"], \"highway\": \"bus_stop\"}\n",
    "gdf = ox.features.features_from_place(\"Piedmont, California, USA\", tags)\n",
    "gdf.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# view just the banks\n",
    "gdf[gdf[\"amenity\"] == \"bank\"].dropna(axis=1, how=\"any\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# view just the bus stops\n",
    "gdf[gdf[\"highway\"] == \"bus_stop\"].dropna(axis=1, how=\"any\").head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Attach features to nearest nodes\n",
    "\n",
    "For example, attach parking information to nearest network nodes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# first create the graph and the features\n",
    "place = \"Piedmont, CA, USA\"\n",
    "G = ox.graph.graph_from_place(place, network_type=\"drive\")\n",
    "features = ox.features.features_from_place(place, {\"amenity\": \"parking\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# then attach your features to your graph's nearest nodes as attributes\n",
    "feature_points = features.representative_point()\n",
    "nn = ox.distance.nearest_nodes(G, feature_points.x, feature_points.y)\n",
    "useful_tags = [\"access\", \"parking\", \"surface\", \"capacity\", \"fee\"]\n",
    "for node, feature in zip(nn, features[useful_tags].to_dict(orient=\"records\")):\n",
    "    feature = {k: v for k, v in feature.items() if pd.notna(v)}\n",
    "    G.nodes[node].update({\"parking\": feature})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
